//
// Created by xue3z on 2025/8/13.
//

#ifndef ASYNCLOGSYSTEM_LOGGER_H
#define ASYNCLOGSYSTEM_LOGGER_H

#include <iostream>
#include <queue>
#include <string>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <fstream>
#include <atomic>
#include <stdexcept>
#include <cstdio>
#include <iomanip>


std::string getCurrentTimeString() {
    // 获取当前系统时间
    auto now = std::chrono::system_clock::now();
    std::time_t now_time = std::chrono::system_clock::to_time_t(now);

    // 转换为本地时间
    std::tm* local_time = std::localtime(&now_time);

    // 格式化为字符串
    std::ostringstream oss;
    oss << std::put_time(local_time, "%Y-%m-%d %H:%M:%S"); // 格式：2023-10-25 14:30:45
    return oss.str();
}

/**
 * 日志队列
 */
class LogQueue
{
public:
    /**
     * push msg to queue
     * @param msg 传入参数
     */
    void push(const std::string& msg)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        queue_.push(msg);
        if (queue_.size()==1)
        {
            cond_var_.notify_one();
        }
    }

    /**
     * pop queue.front to msg
     * @param msg 传出参数
     * @return 成功pop时返回true，当且仅当queue为空且is_shutdown为true时返回false，其余时间挂起
     */
    bool pop(std::string& msg)
    {
        std::unique_lock<std::mutex> locker(mutex_);
        cond_var_.wait(locker, [&]()->bool{return !queue_.empty() || is_shutdown_; });

        if (is_shutdown_ && queue_.empty())
        {
            return false;
        }

        msg = queue_.front();
        queue_.pop();
        return true;
    }
    void shutdown()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        is_shutdown_ = true;
        cond_var_.notify_all();
    }
private:
    std::queue<std::string> queue_;
    std::mutex mutex_;
    std::condition_variable cond_var_;
    bool is_shutdown_ = false;

};

/**
 * 日志类
 */
class Logger
{
public:
    /**
     *
     * @param filename 日志文件路径
     */
    Logger(const std::string& filename)
    :log_file_(filename, std::ios::out|std::ios::app)
    ,exit_flag_(false)
    {
        if (!log_file_.is_open())
        {
            throw std::runtime_error("Can't open log file");
        }

        worker_thread_ = std::thread([&]()
        {
            std::string msg;
            while (log_queue_.pop(msg))
            {
                log_file_<<msg<<std::endl;
            }
        });

    }
    ~Logger()
    {
        exit_flag_ = true;
        log_queue_.shutdown();
        if (worker_thread_.joinable())
        {
            worker_thread_.join();
        }
        if (log_file_.is_open())
        {
            log_file_.close();
        }
    }
    template<typename... Args>
    void log_I(const std::string& format, Args&&... args)
    {
        log_queue_.push("[INFO] [ "+getCurrentTimeString()+" ] "+formatMessage(format, std::forward<Args>(args)...));
    }

    template<typename... Args>
    void log_D(const std::string& format, Args&&... args)
    {
        log_queue_.push("[DEBUG] [ "+getCurrentTimeString()+" ] "+formatMessage(format, std::forward<Args>(args)...));
    }

    template<typename... Args>
    void log_W(const std::string& format, Args&&... args)
    {
        log_queue_.push("[WARNING] [ "+getCurrentTimeString()+" ] "+formatMessage(format, std::forward<Args>(args)...));
    }

    template<typename... Args>
    void log_E(const std::string& format, Args&&... args)
    {
        log_queue_.push("[ERROR] [ "+getCurrentTimeString()+" ] "+formatMessage(format, std::forward<Args>(args)...));
    }
private:
    /**
     * 格式化字符串
     * @tparam Args 可变参数类型
     * @param format 字符串格式
     * @param args 一系列用于填充到format中的参数
     * @return 格式化后的字符串
     */
    template<typename... Args>
    std::string formatMessage(std::string format, Args&&... args)
    {
        char buffer[1024];
        std::snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);
        return std::string(buffer);
    }
    LogQueue log_queue_;
    std::thread worker_thread_;
    std::ofstream log_file_;
    std::atomic<bool> exit_flag_;
};

#endif //ASYNCLOGSYSTEM_LOGGER_H